package _java8新特性._base;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DemoTest {

    // 需求：获取作家集合，打印所有年龄小于18的作家名字，去重
    @Test
    public void test_00() {
        List<Author> authors = getAuthors();
        // 使用匿名内部类
        authors.stream()
                .distinct()
                .filter(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge()<18;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
        // 使用 lambda 表达式：关注 参数和行为，忽略 名字
        authors.stream()
                .distinct()
                .filter(author -> author.getAge()<18)
                .forEach(author -> System.out.println(author.getName()));
    }

    // 创建流
    @Test
    public void test_create() {
        // 数组创建流
        Double[] doubles = {12.3, 45.6, 78.9};
        Stream<Double> doubleStream = Arrays.stream(doubles);
        Stream<Double> doubleStream1 = Stream.of(doubles);
        // 集合创建流 list set
        List<Author> authorList = new ArrayList<>();
        Stream<Author> stream = authorList.stream();
        // map.entrySet 创建流
        Map<String, Integer> map = new HashMap<>();
        map.put("孙悟空", 18);
        map.put("猪八戒", 28);
        map.put("唐僧", 38);
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
        entryStream.filter(new Predicate<Map.Entry<String, Integer>>() {
            @Override
            public boolean test(Map.Entry<String, Integer> entry) {
                return entry.getValue()>20;
            }
        }).forEach(new Consumer<Map.Entry<String, Integer>>() {
                    @Override
                    public void accept(Map.Entry<String, Integer> entry) {
                        System.out.println(entry.getKey());
                    }
        });
    }

    // 需求：打印所有姓名长度大于1的作家的姓名
    @Test
    public void test_filter() {
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getName().length()>1;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
        authors.stream()
                .filter(author -> author.getName().length()>1)
                .forEach(author -> System.out.println(author.getName()));
    }

    // 映射一个类型元素或到另一个类型
    // 需求：打印所有作家的姓名
    @Test
    public void test_map() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                })
                .forEach(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        System.out.println(s);
                    }
                });
        authors.stream()
                .map(author -> author.getAge()+10)
                .forEach(age -> System.out.println(age));
    }

    // distinct 依靠 Object.equals 方法，自己的类需要重写 equals，lombok @EqualsAndHashCode
    // 需求：打印所有作家的姓名，去重
    @Test
    public void test_distinct() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));
    }

    // sorted(空参)，需要提前实现 Comparable 接口
    // sorted(有参)，传入比较器
    // 需求：对作家元素，按照年龄增序排序，去重，打印名字
    @Test
    public void test_sorted() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .forEach(author -> System.out.println(author.getAge()));
        authors.stream()
                .distinct()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o1.getAge() - o2.getAge();
                    }
                }).forEach(author -> System.out.println(author.getAge()));
        authors.stream()
                .distinct()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o2.getAge() - o1.getAge();
                    }
                }).forEach(author -> System.out.println(author.getAge()));
    }

    // 需求：对作家元素，按照年龄增序排序，去重，打印年龄最小的两个作家
    @Test
    public void test_limit() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .limit(1)
                .forEach(author -> System.out.println(author.getAge()));
    }

    // 需求：对作家元素，按照年龄增序排序，去重，打印除了最小的的后两个作家
    @Test
    public void test_skip() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getAge()));
    }

    // 将一个元素 映射为 多个元素的 流，即当get中间结果为list时，为避免多重for循环
    // 需求：打印所有书籍的名字，并去重
    @Test
    public void test_flatMap() {
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(book -> System.out.println(book.getName()));
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));
    }

    // 需求：打印现有书籍的所有分类，不能出现这种格式：哲学，爱情
    @Test
    public void test_flatMap2() {
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .flatMap(new Function<Book, Stream<String>>() {
                    @Override
                    public Stream<String> apply(Book book) {
                        return Arrays.stream(book.getCategory().split("，"));
                    }
                })
                .distinct()
                .forEach(category -> System.out.println(category));
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .flatMap(book -> Arrays.stream(book.getCategory().split("，")))
                .distinct()
                .forEach(category -> System.out.println(category));
    }

    // 遍历集合中的的元素，进行某种操作，该操作通过参数指定
    // 需求：输出所有作家名字，去重，名字加后缀 _test
    @Test
    public void test_forEach() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .distinct()
                .forEach(name -> System.out.println(name+"_test"));
    }

    // 需求：打印作家的书籍数目，去重
    @Test
    public void test_count() {
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

    // 需求：打印所有书籍中评分的最高分
    @Test
    public void test_max() {
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((o1, o2) -> o1 - o2);
        max.ifPresent(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });
        max.ifPresent(integer -> System.out.println(integer));
    }

    // 对处理完的集合，仍需返回
    // 需求：返回一个存放所有作者名字的list
    @Test
    public void test_collect_list() {
        List<Author> authors = getAuthors();
        List<String> nameList = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(nameList);
    }

    // 需求：返回一个存放所有书名的set
    @Test
    public void test_collect_set() {
        List<Author> authors = getAuthors();
        Set<String> nameSet = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getName())
                .collect(Collectors.toSet());
        System.out.println(nameSet);
    }

    // map 需要两个 匿名类参数，分别指明，如何转为 key，如何转为 value
    // 需求：返回一个map，key 为作者名，value 为 List<Book>，如果 key 重复，则使用后者覆盖
    @Test
    public void test_collect_map() {
        List<Author> authors = getAuthors();
        Map<String, List<Book>> map = authors.stream()
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                }, new Function<Author, List<Book>>() {
                    @Override
                    public List<Book> apply(Author author) {
                        return author.getBooks();
                    }
                }, new BinaryOperator<List<Book>>() {
                    @Override
                    public List<Book> apply(List<Book> books, List<Book> books2) {
                        return books2;
                    }
                }));
        System.out.println(map);
        Map<String, List<Book>> map1 = authors.stream()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks(), ((books, books2) -> books2)));
        System.out.println(map1);
    }

    // 需求：返回一个map，key 为作者名，value 为 List<Book>，如果 key 重复，则使用后者覆盖
    @Test
    public void test_collect_map2() {
        List<Author> authors = getAuthors();
        Map<String, Integer> map = authors.stream()
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                }, new Function<Author, Integer>() {
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                }, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) {
                        return integer;
                    }
                }));
        System.out.println(map);
        Map<String, Integer> map1 = authors.stream()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getAge(), (name1, name2) -> name2));
        System.out.println(map1);
    }

    // 有任何一条数据符合要求则返回 true
    // 需求：判断是否有年龄在29岁以上的作家
    @Test
    public void test_anyMatch() {
        List<Author> authors = getAuthors();
        boolean anyMatch = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(anyMatch);
    }

    // 需求：判断是否所有作家的年龄都大于29岁
    @Test
    public void test_allMatch() {
        List<Author> authors = getAuthors();
        boolean allMatch = authors.stream()
                .allMatch(author -> author.getAge() > 29);
        System.out.println(allMatch);
    }

    // 需求：判断是否所有作家的年龄都大于100岁
    @Test
    public void test_noneMatch() {
        List<Author> authors = getAuthors();
        boolean noneMatch = authors.stream()
                .noneMatch(author -> author.getAge() > 100);
        System.out.println(noneMatch);
    }

    // 需求：获取第一个年龄大于10的作家，输出名字
    @Test
    public void test_findFirst() {
        List<Author> authors = getAuthors();
        Optional<Author> optionalAuthor = authors.stream()
                .filter(author -> author.getAge() > 10)
                .findFirst();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
    }

    // 需求：获取任意一个年龄大于10的作家，输出名字
    @Test
    public void test_findAny() {
        List<Author> authors = getAuthors();
        Optional<Author> optionalAuthor = authors.stream()
                .filter(author -> author.getAge() > 10)
                .findAny();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
    }

    // 需求：
    @Test
    public void test_reduce() {
        List<Author> authors = getAuthors();

    }

    // 获取作家集合
    public static List<Author> getAuthors() {
        Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟这里的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上它的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制它的思想", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制它的思想", null);

        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();
        List<Book> books4 = new ArrayList<>();

        books1.add (new Book(1L, "刀的两侧是光明与黑暗", "哲学，爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长，爱情", 99, "讲述如何从失败中明悟真理"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情，个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));
        books3.add(new Book (5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
        return authorList;
    }
}
